#include "mywidget.h"
#include "ui_mywidget.h"
//#include "modbusmaster.h"
#include <QMessageBox>

#include <QModbusTcpClient>
#include <QModbusRtuSerialMaster>
#include <QUrl>
#include <QList>
#include <QString>
#include <QTimer>

#include <QDomDocument>
#include <QFile>
#include <QTextStream>
#include <QDebug>

#include <QValueAxis>
#include <QDateTimeAxis>


MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    this->setWindowTitle("ModBus客户端");
    //modbusMaster=NULL;
    count = 0;
    MaxCount = 20;
    CreatXMLTest(); //创建XML文件

    CreatCharts();

    client=new QModbusTcpClient();
    addressInt = 0;

    timer = new QTimer(this);
    connect(timer,&QTimer::timeout,[=](){
        count++;

        ui->readButton->setText(QString("读取(%1)").arg(count));

        qDebug() << "寄存器："<< addressInt;
         QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters,addressInt,15);

        if (auto *reply = client->sendReadRequest(readUnit,1))
        {
            if (!reply->isFinished())
            {
                // connect the finished signal of the request to your read slot
                connect(reply, &QModbusReply::finished,this,&MyWidget::readready);
            }
            else
            {
                delete reply; // broadcast replies return immediately
            }
        }
        else
        {
            // request error
        }       return;

    });


}

void MyWidget::CreatCharts(){
    //
    series1 = new QLineSeries();
    series1->setColor(QColor(255,0,0));
    // 添加实验数据,可以用 append 方法或者 >> 操作符
    series3 = new QLineSeries(); //焊缝识别状态

    chart1 = new QChart();
    // 将图例隐藏
    chart1->legend()->hide();
    // 关联series，这一步很重要，必须要将series关联到QChart才能将数据渲染出来：
    chart1->addSeries(series1);
    chart1->addSeries(series3);
    // 开启OpenGL，QLineSeries支持GPU绘制，Qt其他有的图表类型是不支持的。
    series1->setUseOpenGL(true);
    // 创建默认的坐标系（笛卡尔坐标）
    chart1->createDefaultAxes();
    chart1->axisY()->setRange(0, 500);
    chart1->axisX()->setRange(1,MaxCount);
    // 设置图表标题
    chart1->setTitle(QStringLiteral("焊缝左右偏差走势分析图"));

    view1 = new QChartView(chart1);
    // 开启抗锯齿，让显示效果更好
    view1->setRenderHint(QPainter::Antialiasing);
    view1->resize(450,200);
    view1->move(10,30);
    view1->setParent(ui->groupBox);
    // 显示图表
    //view->show();

    series2 = new QLineSeries();

    chart2 = new QChart();
    chart2->legend()->hide();
    chart2->addSeries(series2);
    // 开启OpenGL，QLineSeries支持GPU绘制，Qt其他有的图表类型是不支持的。
    series2->setUseOpenGL(true);
    // 创建默认的坐标系（笛卡尔坐标）
    chart2->createDefaultAxes();
    chart2->axisY()->setRange(-40000, 0);
    chart2->axisX()->setRange(1,MaxCount);
    // 设置图表标题
    chart2->setTitle(QStringLiteral("焊缝高度偏差走势分析图"));

    view2 = new QChartView(chart2);
    // 开启抗锯齿，让显示效果更好
    view2->setRenderHint(QPainter::Antialiasing);
    view2->resize(450,200);
    view2->move(10,250);
    view2->setParent(ui->groupBox);
    // 显示图表
    //view->show();
}

void MyWidget::CreatXMLTest(){
    //打开或创建文件       return;

    QFile file("test.xml"); //相对路径、绝对路径、资源路径都可以
    if(!file.open(QFile::WriteOnly|QFile::Truncate)) {
        return;
    }//可以用QIODevice，Truncate表示清空原来的内容

    QDomDocument doc;
    //写入xml头部
    QDomProcessingInstruction instruction; //添加处理命令
    instruction=doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(instruction);
    //添加根节点
    QDomElement root=doc.createElement("data");
    doc.appendChild(root);

//    //添加第一个子节点及其子元素
//    QDomElement book=doc.createElement("content");


//    QDomElement index=doc.createElement("index"); //创建子元素
//    QDomText text; //设置括号标签中间的值
//    text=doc.createTextNode("0");
//    book.appendChild(index);
//    index.appendChild(text);

//    QDomElement hfsbState=doc.createElement("hfsbState");
//    text=doc.createTextNode("0");
//    hfsbState.appendChild(text);
//    book.appendChild(hfsbState);

//    QDomElement hfType=doc.createElement("hfType");
//    text=doc.createTextNode("0");
//    hfType.appendChild(text);
//    book.appendChild(hfType);

//    QDomElement hfZYValue=doc.createElement("hfZYValue");
//    text=doc.createTextNode("0");
//    hfZYValue.appendChild(text);
//    book.appendChild(hfZYValue);

//    QDomElement hfHValue=doc.createElement("hfHValue");
//    text=doc.createTextNode("0");
//    hfHValue.appendChild(text);
//    book.appendChild(hfHValue);

//    QDomElement JgOpenState=doc.createElement("JgOpenState");
//    text=doc.createTextNode("0");
//    JgOpenState.appendChild(text);
//    book.appendChild(JgOpenState);

//    QDomElement lxPzState=doc.createElement("lxPzState");
//    text=doc.createTextNode("0");
//    lxPzState.appendChild(text);
//    book.appendChild(lxPzState);

//    root.appendChild(book);

    //输出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream,4); //缩进4格
    file.close();
}

MyWidget::~MyWidget()
{
    delete ui;
}

void MyWidget::on_clinckButton_clicked()
{
    if (client->state() != QModbusDevice::ConnectedState){
        const QUrl url = QUrl::fromUserInput(ui->lineEdit->text());
        client->setConnectionParameter(QModbusDevice::NetworkAddressParameter,url.host());
        client->setConnectionParameter(QModbusDevice::NetworkPortParameter,url.port());
        client->setTimeout(200);
        client->setNumberOfRetries(1);

        if(!client->connectDevice()){
                qDebug()<<QString("There's something wrong with the device");
                QString str = "连接状态：连接失败";
                ui->statusLabel->setText(str);
            }else {
                qDebug()<<QString("Right connection");
                QString str = "连接状态：连接成功";
                ui->statusLabel->setText(str);
                ui->clinckButton->setText("断开");

                //connect(client,&QModbusTcpClient::stateChanged,this,&MyWidget::query);
            }
    }else{
        client->disconnectDevice();
        qDebug()<<QString("Right disconnection");
        QString str = "连接状态：断开连接";
        ui->statusLabel->setText(str);
        ui->clinckButton->setText("连接");
        ui->textEdit->clear();
        timer->stop();

        ui->ContentEdit->clear();
    }

}

void MyWidget::query(){
    //QModbusDataUnit readUnit(QModbusDataUnit::Coils,00000,4);
    qDebug() << "寄存器："<< addressInt;
     QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters,addressInt,1);

    if (auto *reply = client->sendReadRequest(readUnit,1))
    {
        if (!reply->isFinished())
        {
            // connect the finished signal of the request to your read slot
            connect(reply, &QModbusReply::finished,this,&MyWidget::readready);
        }
        else
        {
            delete reply; // broadcast replies return immediately
        }
    }
    else
    {
        // request error
    }
}

void MyWidget::readready(){
    QModbusReply *reply=qobject_cast<QModbusReply *>(sender());
    const QModbusDataUnit result=reply->result();
    qDebug() << "value:" << result.values();

    QStringList list;
    for (int i=0;i<result.valueCount();i++){
        //qDebug()<<QString("The value of %1 is %2").arg(i).arg(result.value(i));
        QString str1;
        //转16进制
        //str1= QString::number(result.value(i),16);
        int16_t data = result.value(i);
        str1 = QString("%1").arg(data);

        list.append(str1);
    }
    QString str = list.join(",");
    ui->textEdit->setText(str);

    //获取寄存器内容
    QString content;
    QString jgType = QString("%1").arg(result.value(0));
    if(jgType == "0"){
       content += "激光类型暂无\n";
    }else {
       content += "激光类型：ＸＸＸ\n";
    }

    QString jgState =  QString("%1").arg(result.value(1));
    if (jgState =="0"){
        content += "激光发射器关闭\n";
    }else{
        content += "激光发射器已开启\n";
    }

    QString lxpzState = QString("%1").arg(result.value(2));
    if (lxpzState =="0"){
        content += "连续拍照并识别焊缝关闭\n";
    }else{
        content += "连续拍照并识别焊缝已开启\n";
    }

    QString hfsbState = QString("%1").arg(result.value(9));
    if (hfsbState =="0"){
        content += "焊缝未识别\n";
        series3->append(count,0);
    }else{
        content += "焊缝已识别\n";
        series3->append(count,255);
    }

    int16_t data1 = result.value(11);
    QString pcContentStr = QString("焊缝左右偏差：%1, 焊缝高度值: %2").arg(result.value(10)).arg(data1);
    content += pcContentStr;
    ui->ContentEdit->setText(content);

    series1->append(count,result.value(10));
    series2->append(count,data1);

    if(count>MaxCount){
        //CreatXMLTest();
        chart1->axisX()->setMin(count);
        chart2->axisX()->setMin(count);
        MaxCount = MaxCount +20;
        chart1->axisX()->setMax(MaxCount);
        chart2->axisX()->setMax(MaxCount);
    }
    else{
        //XML文件写入
        //打开文件
        QFile file("test.xml"); //相对路径、绝对路径、资源路径都可以
        if(!file.open(QFile::ReadOnly))
            return;

        //增加一个一级子节点以及元素
        QDomDocument doc;
        if(!doc.setContent(&file))
        {
            file.close();
            return;
        }
        file.close();

        QDomElement root=doc.documentElement();
        QDomElement book=doc.createElement("content");

        QDomElement index=doc.createElement("index");
        QDomText text;
        text=doc.createTextNode(QString("%1").arg(count));
        index.appendChild(text);
        book.appendChild(index);

        QDomElement hfsb=doc.createElement("hfsbState");
        text=doc.createTextNode(hfsbState);
        hfsb.appendChild(text);
        book.appendChild(hfsb);

        QDomElement hfType=doc.createElement("hfType");
        text=doc.createTextNode(jgType);
        hfType.appendChild(text);
        book.appendChild(hfType);

        QDomElement hfZYValue=doc.createElement("hfZYValue");
        text=doc.createTextNode(QString("%1").arg(result.value(10)));
        hfZYValue.appendChild(text);
        book.appendChild(hfZYValue);

        QDomElement hfHValue=doc.createElement("hfHValue");
        text=doc.createTextNode(QString("%1").arg(data1));
        hfHValue.appendChild(text);
        book.appendChild(hfHValue);

        QDomElement JgOpenState=doc.createElement("JgOpenState");
        text=doc.createTextNode(jgState);
        JgOpenState.appendChild(text);
        book.appendChild(JgOpenState);

        QDomElement lxPzState=doc.createElement("lxPzState");
        text=doc.createTextNode(lxpzState);
        lxPzState.appendChild(text);
        book.appendChild(lxPzState);
        root.appendChild(book);

        if(!file.open(QFile::WriteOnly|QFile::Truncate)) //先读进来，再重写，如果不用truncate就是在后面追加内容，就无效了
            return;
        //输出到文件
        QTextStream out_stream(&file);
        doc.save(out_stream,4); //缩进4格
        file.close();
    }

}

void MyWidget::on_readButton_clicked()
{
    if (client->state() != QModbusDevice::ConnectedState){
        QMessageBox::information(NULL, "information", "未连接", QMessageBox::Yes );
    }else {
        qDebug() << "可以读取";
        timer->start(500);
    }
}

void MyWidget::on_comboBox_currentIndexChanged(int index)
{
    addressInt = index;
}

void MyWidget::on_cancelButton_clicked()
{
    if (client->state() != QModbusDevice::ConnectedState){
        QMessageBox::information(NULL, "information", "未连接", QMessageBox::Yes );
    }else {
        qDebug() << "取消读取";
        timer->stop();
    }
}

void MyWidget::on_readXMLButton_clicked()
{
    //打开或创建文件
    QFile file("test.xml"); //相对路径、绝对路径、资源路径都行
    if(!file.open(QFile::ReadOnly))
        return;

    QDomDocument doc;
    if(!doc.setContent(&file))
    {
        file.close();
        return;
    }
    file.close();

    QDomElement root=doc.documentElement(); //返回根节点
    qDebug()<<root.nodeName();
    QDomNode node=root.firstChild(); //获得第一个子节点
    while(!node.isNull())  //如果节点不空
    {
        if(node.isElement()) //如果节点是元素
        {
            QDomElement e=node.toElement(); //转换为元素，注意元素和节点是两个数据结构，其实差不多
            //qDebug()<<e.tagName()<<" "<<e.attribute("id")<<" "<<e.attribute("time"); //打印键值对，tagName和nodeName是一个东西
            QDomNodeList list=e.childNodes();
            for(int i=0;i<list.count();i++) //遍历子元素，count和size都可以用,可用于标签数计数
            {
                QDomNode n=list.at(i);
                if(node.isElement())
                    qDebug()<<n.nodeName()<<":"<<n.toElement().text();
            }
        }
        node=node.nextSibling(); //下一个兄弟节点,nextSiblingElement()是下一个兄弟元素，都差不多
    }
}

void MyWidget::WriteModbus(int addressName, quint16 strContent){
    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, addressName, 1);
    writeUnit.setValue(0, strContent);
    //这里先建好QModbusDataUnit

    if (auto *reply = client->sendWriteRequest(writeUnit, 1))
    //发送写请求
    {
        if (!reply->isFinished())
        {
            connect(reply, &QModbusReply::finished, this, [this, reply]()
            {
                if (reply->error() != QModbusDevice::NoError)
                        // error in reply

                    reply->deleteLater();
                });
        }
        else
        {
            if (reply->error() != QModbusDevice::NoError)
                // error in reply

            // broadcast replies return immediately
            reply->deleteLater();
        }
    }
    else
    {
        // error in request
    }
}

void MyWidget::on_JGOpenButton_clicked()
{
    WriteModbus(1,255);
}

void MyWidget::on_JGCloseButton_clicked()
{
     WriteModbus(1,0);
}

void MyWidget::on_LXOpenButton_clicked()
{
    WriteModbus(2,255);
}

void MyWidget::on_LXCloseButton_clicked()
{
    WriteModbus(2,0);
}
